<template>
  <section class="bg-purple-950 p-[10px] h-screen w-full">
    <!-- tab 栏 -->
    <el-row>
      <div class="flex flex-row flex-1 align-bottom">
        <button
          class="mr-[10px] py-1 px-6 bg-white text-purple-900 shadow-lg shadow-purple-900/50 text-[14px] rounded-[4px]"
          @click="clearRequest">
          清除请求
        </button>
        <button
          class="mr-[10px] py-1 px-6 bg-white text-purple-900 shadow-lg shadow-purple-900/50 text-[14px] rounded-[4px]"
          @click="clearFix">
          清除固定
        </button>
        <button
          class="mr-[10px] py-1 px-6 bg-white text-purple-900 shadow-lg shadow-purple-900/50 text-[14px] rounded-[4px]"
          @click="listSort">
          {{ state.sortList ? "降序" : "升序" }}
        </button>

        <el-select v-model="state.option" class="mr-[10px]">
          <el-option v-for="item in state.options" :key="item.value" :label="item.label" :value="item.value">
            <span class="text-purple-900">{{ item.label }}</span>
          </el-option>
        </el-select>

        <div class="w-[300px] mr-[10px]">
          <el-input v-model="state.searchKey" placeholder="请输入URL关键词" @change="filterBySearchKey" />
        </div>
      </div>
      <button
        class="mr-[10px] py-1 px-6 bg-white text-purple-900 shadow-lg shadow-purple-900/50 text-[14px] rounded-[4px]"
        @click="state.showMore = true">
        更多
      </button>
    </el-row>
    <el-row class="mt-3 h-[95%] flex-1">
      <!-- 固定请求 -->
      <ul class="bg-purple-900 rounded-[10px] overflow-auto text-amber-600 p-3 w-full h-[20%] scrollbar mb-2">
        <li v-for="(item, index) in fixMap.values()" :key="index">
          <div class="flex flex-row items-center py-2 hover:bg-purple-800 hover:rounded-md"
            v-if="state.option === 'ALL' || state.option === item.method?.toUpperCase()">
            <p class="w-[90px] pl-2 text-center text-xs">{{ item.label }}</p>

            <p
              class="w-[80px] h-[28px] text-center leading-[28px] font-bold mr-[10px] border border-[#fff] rounded-[5px] text-[#fff]">
              {{ item.plat }}
            </p>
            <p :class="[
              'w-[70px] h-[30px] text-center text-[#fff] leading-[30px] font-bold mr-[10px] rounded-[5px]',
              item.method === 'GET' ? 'bg-[#59C18C]' : 'bg-[#6D6DF7]',
            ]">
              {{ item.method }}
            </p>
            <div class="flex justify-center items-center mr-[10px]" @click="cancelRequest(item)">
              <el-icon :size="20" color="red"><i-ep-CircleClose /></el-icon>
            </div>
            <p class="italic text-ellipsis overflow-hidden font-bold flex-1 my-auto" style="text-wrap: nowrap">
              {{ item.url }}
            </p>
            <log-button :data="item" @showJSON="showJSON"></log-button>
          </div>
        </li>
      </ul>
      <!-- 普通请求 -->
      <ul class="bg-purple-900 rounded-[10px] overflow-auto text-white p-3 w-full h-[77%] scrollbar">
        <li v-for="(item, index) in data" :key="index">
          <div class="flex flex-row items-center py-2 hover:bg-purple-800 hover:rounded-md"
            v-if="state.option === 'ALL' || state.option === item.method?.toUpperCase()">
            <p class="w-[90px] mr-[5px] pl-2 text-center text-xs">{{ item.label }}</p>
            <p
              class="w-[80px] h-[28px] text-center leading-[28px] font-bold mr-[10px] border border-[#fff] rounded-[5px]">
              {{ item.plat }}
            </p>
            <p :class="[
              'w-[70px] h-[30px] text-center leading-[30px] font-bold mr-[10px] rounded-[5px]',
              item.method === 'GET' ? 'bg-[#59C18C]' : 'bg-[#6D6DF7]',
            ]">
              {{ item.method }}
            </p>
            <div class="flex justify-center items-center mr-[10px]" @click="removeItem(item)">
              <el-icon :size="20" color="red"><i-ep-CircleClose /></el-icon>
            </div>
            <p class="italic text-ellipsis overflow-hidden font-bold flex-1 my-auto" style="text-wrap: nowrap">
              {{ item.url }}
            </p>
            <button
              class="mx-[10px] py-2 px-6 bg-purple-950 shadow-lg shadow-purple-500/50 text-[12px] rounded-md font-bold"
              @click="fixRequest(item)">
              固定
            </button>
            <log-button :data="item" @showJSON="showJSON"></log-button>
          </div>
        </li>
      </ul>
    </el-row>

    <!-- JSON预览 -->
    <el-dialog v-model="state.showJSON" width="1200px" @close="hideJSON" append-to-body>
      <template #header>
        <div class="text-white text-center font-bold text-[18px]">JSON预览</div>
      </template>
      <!-- JSON -->
      <json-view :data="page.currentRequest"></json-view>
      <!-- 按钮 -->
      <template #footer>
        <div class="dialog-footer">
          <button v-if="page.request && !fixMap.has(page.request.time)"
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="page.request && fixRequest(page.request)">
            固定
          </button>
          <button
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="copyStr(page.currentRequest.url)">
            URL
          </button>
          <button v-if="page.currentRequest?.method?.toUpperCase() === 'POST'"
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="copyStr(JSON.stringify(page.currentRequest.params))">
            query/body
          </button>
          <button v-if="page.currentRequest.response"
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="copyStr(JSON.stringify(page.currentRequest.response))">
            response
          </button>
          <button
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="copyJSON">
            ALL
          </button>
          <button
            class="mx-[10px] py-2 px-6 text-white bg-purple-500 shadow-lg shadow-purple-900/50 text-[12px] rounded-md"
            @click="hideJSON">
            关闭
          </button>
        </div>
      </template>
    </el-dialog>

    <!-- 更多视图 -->
    <button-more v-model="state.showMore" :copyStr="copyStr" />
  </section>
</template>

<script lang="ts" setup>
import socket, { IP } from "@/utils/WebSocket";
import { dayjs } from "element-plus";
import useClipboard from 'vue-clipboard3';
const { toClipboard } = useClipboard();

const state = reactive({
  URL: IP,
  sortList: false,
  showJSON: false,
  searchKey: "",
  option: "ALL",
  options: [
    {
      label: "全部",
      value: "ALL",
    },
    {
      label: "GET请求",
      value: "GET",
    },
    {
      label: "POST请求",
      value: "POST",
    },
  ],
  showMore: false,
});

const page = shallowReactive<{ currentRequest: any; request: logRequest | null }>({
  currentRequest: "",
  request: null,
});

type logRequest = {
  label: string; // 标题
  plat: string; // 来源
  url: string; // 请求路径
  method: string; // 方法
  body: any; // 请求响应体
  time: number; // 时间
};
const data = ref<logRequest[]>([]);
const fixMap = ref<Map<number, logRequest>>(new Map());

socket.addEventListener("message", (event) => {
  try {
    const { data: obj } = event;
    const json = JSON.parse(obj);
    const { url = "", method = "", plat = "" } = json;
    const _ = {
      label: dayjs().format("YYYY-MM-DD HH:mm:ss"),
      plat,
      url,
      method,
      body: json,
      time: new Date().getTime(),
    };
    return getRequestData(_);
  } catch (e) {
    console.log("socket :>> Err", e);
  }
});

const getRequestData = (_: logRequest) => {
  const { searchKey } = state;
  // 路径过滤
  if (searchKey && !_.url.includes(searchKey)) {
    return;
  }
  if (state.sortList) {
    // 升序
    data.value.push(_);
  } else {
    // 降序
    data.value.unshift(_);
  }
};

const clearRequest = () => {
  data.value = [];
};

const copyStr = (str: string) => {
  if (!str) return;
  if (navigator.clipboard) {
    navigator.clipboard.writeText(str || "").then(() => {
      Utils.Modal().msgSuccess("已复制剪切版~");
    });
  } else {
    toClipboard(str).then(() => {
      Utils.Modal().msgSuccess("已复制剪切版~");
    });
  }
};

const showJSON = (json: any) => {
  page.request = json;
  page.currentRequest = json.body;
  state.showJSON = true;
};

const hideJSON = () => {
  page.request = null;
  page.currentRequest = "";
  state.showJSON = false;
};
const copyJSON = () => {
  copyStr(JSON.stringify(page.currentRequest || ""));
};

const clearFix = () => {
  fixMap.value.clear();
};

const fixRequest = (req: logRequest) => {
  if (!fixMap.value.has(req.time)) {
    fixMap.value.set(req.time, req);
    state.showJSON = false;
  }
};

const cancelRequest = (req: logRequest) => {
  fixMap.value.delete(req.time);
};

const listSort = () => {
  state.sortList = !state.sortList;
  data.value.reverse();
};

const removeItem = (item: logRequest) => {
  data.value = data.value.filter((_) => _.url !== item.url);
};

const filterBySearchKey = () => {
  const { searchKey } = state;
  data.value = data.value.filter((_) => _.url.includes(searchKey));
};
</script>

<style scope>
.scrollbar::-webkit-scrollbar {
  width: 5px;
  height: 20px;
}

.scrollbar::-webkit-scrollbar-track {
  border-radius: 100vh;
  background: rgb(88 28 135);
}

.scrollbar::-webkit-scrollbar-thumb {
  background: rgb(59 7 100);
  border-radius: 100vh;
  border: 1px solid #cccccc;
}

.scrollbar::-webkit-scrollbar-thumb:hover {
  background: rgb(88 28 135);
}

.el-dialog {
  --el-dialog-margin-top: 30px;
  background: rgb(88 28 135);
}

.el-dialog__body {
  padding-top: 0;
}

.vjs-tree-node:hover {
  background-color: rgb(88 28 135);
  font-weight: bold;
  color: #fff;
}
</style>
